import {
  computed,
  defineComponent,
  onMounted,
  ref,
  watch,
  type ExtractPropTypes,
} from 'vue';

// Composables
import { useEventListener } from '../../use/useEventListener';

import './highlight.scss';

export const textEllipsisProps = {
  rows: {
    type: Number,
    default() {
      return 1;
    },
  },
  dots: {
    type: String,
    default() {
      return '...';
    },
  },
  content: {
    type: String,
    default() {
      return '';
    },
  },
  expandText: {
    type: String,
    default() {
      return '';
    },
  },
  collapseText: {
    type: String,
    default() {
      return '';
    },
  },
  position: {
    type: String,
    default() {
      return "end"
    },
  },
  index:{
    type: Number,
    default() {
      return 0
    },
  },
  getValHighlight:{type:Function,default(str){return str}},
  rawContent: {
    type: String,
    default() {
      return '';
    },
  },
};

export type TextEllipsisProps = ExtractPropTypes<typeof textEllipsisProps>;

export default defineComponent({

  props: textEllipsisProps,

  emits: ['clickAction'],

  setup(props, { emit, slots }) {
    const text = ref('');
    const expanded = ref(false);
    const hasAction = ref(false);
    const root = ref<HTMLElement>();

    const actionText = computed(() =>
      expanded.value ? props.collapseText : props.expandText,
    );

    const pxToNum = (value: string | null) => {
      if (!value) return 0;
      const match = value.match(/^\d*(\.\d*)?/);
      return match ? Number(match[0]) : 0;
    };

    const calcEllipsised = () => {
      const cloneContainer = () => {
        // debugger;
        if (!root.value) return;

        const originStyle = window.getComputedStyle(root.value);
        const container = document.createElement('div');
        const styleNames: string[] = Array.prototype.slice.apply(originStyle);
        styleNames.forEach(name => {
          container.style.setProperty(name, originStyle.getPropertyValue(name));
        });

        container.style.position = 'fixed';
        container.style.zIndex = '-9999';
        container.style.top = '-9999px';
        container.style.height = 'auto';
        container.style.minHeight = 'auto';
        container.style.maxHeight = 'auto';

        container.innerText = props.rawContent || props.content;
        container.innerHTML = container.innerText;
        document.body.appendChild(container);
        return container;
      };

      const calcEllipsisText = (
        container: HTMLDivElement,
        maxHeight: number,
      ) => {
        const { rawContent: content, position, dots, getValHighlight } = props;
        const end = content.length;

        const calcEllipse = () => {
          // calculate the former or later content
          const tail = (left: number, right: number): string => {
            if (right - left <= 1) {
              if (position === 'end') {
                return (content.slice(0, left)) + dots;
              }
              return dots + (content.slice(right, end));
            }

            const middle = Math.round((left + right) / 2);

            // Set the interception location
            if (position === 'end') {
              container.innerText =
              (content.slice(0, middle)) + dots + actionText.value;
            } else {
              container.innerText =
                dots + (content.slice(middle, end)) + actionText.value;
            }

            // The height after interception still does not match the rquired height
            if (container.offsetHeight > maxHeight) {
              if (position === 'end') {
                return tail(left, middle);
              }
              return tail(middle, right);
            }

            if (position === 'end') {
              return tail(middle, right);
            }

            return tail(left, middle);
          };

          container.innerText = tail(0, end);
          // container.innerHTML = getValHighlight(container.innerText)
        };

        const middleTail = (
          leftPart: [number, number],
          rightPart: [number, number],
        ): string => {
          if (
            leftPart[1] - leftPart[0] <= 1 &&
            rightPart[1] - rightPart[0] <= 1
          ) {
            return (
              content.slice(0, leftPart[0]) +
              dots +
              content.slice(rightPart[1], end)
            );
          }

          const leftMiddle = Math.floor((leftPart[0] + leftPart[1]) / 2);
          const rightMiddle = Math.ceil((rightPart[0] + rightPart[1]) / 2);

          container.innerText =
            props.content.slice(0, leftMiddle) +
            props.dots +
            props.content.slice(rightMiddle, end) +
            props.expandText;
          container.innerHTML = container.innerText;

          if (container.offsetHeight >= maxHeight) {
            return middleTail(
              [leftPart[0], leftMiddle],
              [rightMiddle, rightPart[1]],
            );
          }

          return middleTail(
            [leftMiddle, leftPart[1]],
            [rightPart[0], rightMiddle],
          );
        };

        const middle = (0 + end) >> 1;
        props.position === 'middle'
          ? (container.innerText = middleTail([0, middle], [middle, end]))
          : calcEllipse();
        return container.innerText;
      };

      // Calculate the interceptional text
      const container = cloneContainer();
      if (!container) return;
      const { paddingBottom, paddingTop, lineHeight } = container.style;
      const maxHeight = Math.ceil(
        (Number(props.rows) + 0.5) * pxToNum(lineHeight) +
          pxToNum(paddingTop) +
          pxToNum(paddingBottom),
      );

      if (maxHeight < container.offsetHeight) {
        hasAction.value = true;
        text.value = props.getValHighlight(calcEllipsisText(container, maxHeight));
      } else {
        hasAction.value = false;
        text.value = props.content;
      }

      document.body.removeChild(container);
    };

    const onClickAction = (event: MouseEvent) => {
      expanded.value = !expanded.value;
      emit('clickAction', event);
    };


    const bem = (n?) => {
      return `t-text-ellipsis${n ? '__' + n : ''}`;
    };

    const renderAction = () => (
      <span class={(bem('action'))} onClick={onClickAction}>
        {!expanded.value
          ? slots.expand
            ? slots.expand()
            : actionText.value
          : slots.collapse
            ? slots.collapse()
            : actionText.value}
        {/* {expanded.value && slot.expand ? slot.expand() : actionText.value}
        {!expanded.value && slot.collapse ? slot.collapse() : actionText.value} */}
      </span>
    );

    onMounted(calcEllipsised);

    watch(() => [props.content, props.rows, props.position], calcEllipsised);

    useEventListener('resize', calcEllipsised);

    return () => (
      <div
        ref={root}
        class={[bem(),'fields', props.index==0 ? 'first' : ''  ]}
      >
        <span class='t-text-ellipsis-span-highlight' innerHTML={expanded.value ? props.content : text.value }></span>
        {hasAction.value ? renderAction() : null}
      </div>
    );
  },
});
